package utils

import (
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/util/gconv"
	"strings"
)

type sArray struct {
	Data interface{}
}

// Columns 根据字段取出新切片数据
func (a sArray) Columns(field string) ([]interface{}, error) {
	// 统一转换为二维数组MAP
	slicesList := gconv.Maps(a.Data)
	if len(slicesList) == 0 {
		return nil, gerror.New(`数据为空`)
	}
	// 处理数据
	slices := make([]interface{}, 0)
	for _, slice := range slicesList {
		if _, ok := slice[field]; !ok {
			return nil, gerror.New(`数据字段` + field + `不存在`)
		}
		slices = append(slices, slice[field])
	}
	return slices, nil
}

// Map 二维数据字段合集Map
func (a sArray) Map(field string) (map[interface{}]interface{}, error) {
	// 统一转换为二维数组MAP
	slicesList := gconv.Maps(a.Data)
	if len(slicesList) == 0 {
		return nil, gerror.New(`数据为空`)
	}
	// 转换数据
	sMap := make(map[interface{}]interface{})
	for _, slice := range slicesList {
		if _, ok := slice[field]; !ok {
			return nil, gerror.New(`数据字段` + field + `不存在`)
		}
		sMap[slice[field]] = slice
	}
	return sMap, nil
}

// Unique 二维数组去重并获取字段集合
func (a sArray) Unique(field string) []interface{} {
	slices, err := a.Columns(field)
	if err != nil {
		return nil
	}
	// 数据为空
	if len(slices) == 0 {
		return nil
	}
	var (
		slicesUni = make([]interface{}, 0)
		dedup     = make(map[interface{}]bool)
	)
	// 处理去重
	for _, slice := range slices {
		if _, ok := dedup[slice]; ok {
			continue
		}
		slicesUni = append(slicesUni, slice)
	}
	return slicesUni
}

// Units 数组集合转Uint类型
func (a sArray) Units(field string) []uint {
	// 处理数据
	slices := a.Unique(field)
	if len(slices) == 0 {
		return nil
	}
	arr := make([]uint, 0)
	for _, slice := range slices {
		switch v := slice.(type) {
		case uint:
			arr = append(arr, v)
		}
	}
	return arr
}

// Strings 数组集合转String类型
func (a sArray) Strings(field string) []string {
	// 处理数据
	slices := a.Unique(field)
	if len(slices) == 0 {
		return nil
	}
	arr := make([]string, 0)
	for _, slice := range slices {
		switch v := slice.(type) {
		case string:
			arr = append(arr, v)
		default:
			arr = append(arr, gconv.String(v))
		}
	}
	return arr
}

// IsExists 验证指定值是否存在数组数列中
func (a sArray) IsExists(i interface{}) (bool, error) {
	arr := gconv.SliceAny(a.Data)
	if len(arr) == 0 {
		return false, gerror.New(`Array IsExists 格式错误`)
	}
	// 转换为字符串
	s := gconv.String(i)
	for _, val := range arr {
		if s == gconv.String(val) {
			return true, nil
		}
	}
	return false, nil
}

// MustIsExists 验证指定值是否存在数组数列中
func (a sArray) MustIsExists(i interface{}) bool {
	is, _ := a.IsExists(i)
	return is
}

// GenCombinations 生成数据集合
// Example
// values := []string{`淘宝`,`美妆`,`双十一`}
// fmt.Println(GenCombinations(values, `-`))
// Result:
// 淘宝
// 淘宝-美妆
// 淘宝-双十一
// 淘宝-美妆-双十一
func GenCombinations(values []string) [][]string {
	// 不能为空且只有一个值
	if len(values) == 0 {
		return nil
	}

	// 初始化
	var (
		combinations [][]string // 二维集合
		current      []string   // 当前切片
		backtrack    func(int)
	)

	// 回溯循环递归
	backtrack = func(start int) {
		if len(current) > 0 {
			// 创建一个新的切片，避免后续修改影响已加入combinations的切片
			copyTemp := make([]string, len(current))
			copy(copyTemp, current)
			combinations = append(combinations, copyTemp)
		}

		for i := start; i < len(values); i++ {
			current = append(current, values[i])
			backtrack(i + 1)                   // 不重复添加同一元素
			current = current[:len(current)-1] // 回溯，移除当前元素
		}
	}

	// 初始化执行
	backtrack(0)
	return combinations
}

// GenCombinationsString 生成数据集合
// Example
// values := []string{`淘宝`,`美妆`,`双十一`}
// fmt.Println(GenCombinationsString(values, `-`))
// Result:
// 淘宝
// 淘宝-美妆
// 淘宝-双十一
// 淘宝-美妆-双十一
func GenCombinationsString(values []string, sep string) []string {
	// 不能为空且只有一个值
	switch len(values) {
	case 0:
		return nil
	case 1:
		return values
	}
	// 生成计算集合
	combinations := GenCombinations(values)

	// 创建新的集合切片
	var slices []string
	for _, combo := range combinations {
		slices = append(slices, strings.Join(combo, sep))
	}
	return slices
}
